home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / sound2.cx < prev    next >
Text File  |  1999-01-09  |  18KB  |  576 lines

  1. /****************************   Sound.c   *********************************
  2.  
  3.     Sound is copyright (c) 1988 by Richard Lee Stockton, 21305 60th Ave W.,
  4. Mountlake Terrace, Washington 98043, 206/776-1253(voice), but may be freely
  5. distributed as long as no profit is made from its distribution or sale
  6. without my written permission. I call this concept 'FreeWare', you can
  7. call it whatcha want.
  8.  
  9.     I also include the source code, (Manx Aztec 5.0d), in the hope that it
  10. will be of benefit to someone in the Amiga programming community. Feel free
  11. to alter it at will, (but at your own risk!). I _would_ appreciate
  12. receiving a copy of whatever it may become and it is always nice to receive
  13. credit, (perhaps just a few lines of glowing tribute.^)
  14.  
  15.                Long Live Leo and All the Little Schwabies!
  16.  
  17.                      To Manufacture with Manx 5.0d
  18.  
  19.                         cc -ps -safnps Sound.c
  20.                         ln +cdb Sound.o -lc16
  21.  
  22.  
  23. **************************************************************************/
  24.  
  25. #include <exec/memory.h>
  26. //#include <workbench/startup.h>
  27. //#include <workbench/workbench.h>
  28. //#include <workbench/icon.h>
  29. //#include <libraries/dosextens.h>
  30. //#include <graphics/gfxbase.h>
  31. #include <devices/audio.h>
  32. #include <string.h>
  33. #include <functions.h>
  34.  
  35. #include "sound2_protos.h"
  36.  
  37. /* Less than WorkBench 1.2 need not apply. That's nobody, right? ;-> */
  38.  
  39. #define  REVISION   33L
  40.  
  41. /* We'll need 4 buffers in CHIP memory, all else in FAST, if ya got it */
  42.  
  43. long  BUFSIZE = 1024L;
  44.  
  45. /* A pretty little HELP message showing valid variable ranges */
  46.  
  47. //#define  USAGE      "\
  48. //\033[42m\033[31m\
  49. // USAGE: Sound <file> [56-65535] [v1-v64] [0-55] [e1-e64] [dfglrsq] \
  50. //\033[m\n\033[42m\
  51. // ABORT: <CTRL> 'c'\033[33m\
  52. //  SAMPLES/SEC  VOLUME  CYCLES  END_VOL   FLAGS   \
  53. //\033[m\n\033[42m\033[31m\
  54. // GRAMMA SOFTWARE * freely distributable * 07 Mar \xA9 1991 RLStockton \
  55. //\033[m\n"
  56.  
  57. /* Probably more GLOBALS than are required. 'C' is funny stuff. */
  58.  
  59. //extern struct   GfxBase       *GfxBase=NULL;
  60. //extern struct   IconBase      *IconBase=NULL;
  61. //extern struct   IntuitionBase *IntuitionBase=NULL;
  62. //extern struct   MsgPort       *CreatePort();
  63. //extern struct   WBStartup     *WBenchMsg=NULL;
  64. //extern struct   WBArg         *argp=NULL;
  65. //       struct   IntuiMessage  *message=NULL;
  66. //       struct   Window        *StatusWindo=NULL;
  67.        struct   DiskObject    *infofile=NULL;
  68.        struct   IOAudio       *sound[4]={NULL,NULL,NULL,NULL};
  69.        struct   Filehandle    *sFile=NULL;
  70.        struct   FileLock      *lock=NULL, *savelock=NULL;
  71.                 long          sactual=0L, sstart=0L, vol=64L, fade=0L,
  72.                                atol(), sps=0L, cycles=1L, startvol=64L,
  73.                                endvol=64L, fadevol=0L;
  74.                 short         k=0, stereo=0, left=1, right=1, compflag=0,
  75.                                statusline=1, direct=0;
  76.                 UBYTE         sunit[4]={12,10,5,3},
  77.                                sunitL[2]={1,8}, sunitR[2]={2,4};
  78.                 BOOL          help=FALSE;
  79.                 char          *sbuffer=NULL, *ltoa(), title[108]="",
  80.                                *cbuf[4]={NULL,NULL,NULL,NULL},
  81.                                sname[108], *SafeAllocMem(),
  82.                                *portname[4]={"Snd0","Snd1","Snd2","Snd3"},
  83.                                comptable[16]={-34,-21,-13,-8,-5,-3,-2,-1,
  84.                                      0,1,2,3,5,8,13,21};
  85.                 void          loadSound(), setStatusWindo(),
  86.                                soundSound(), cleanup(), snd_quit();
  87.  
  88. short svol=64;
  89.  
  90. /*********** quit, give-up, go home, finish... Neatness counts! ******/
  91.  
  92. void snd_quit(qstring)
  93. char    *qstring;
  94. {
  95.    cleanup(qstring);   
  96.    return;
  97. }
  98.  
  99. void cleanup(string)
  100. char    *string;
  101. {
  102.    if(sound[0])      /* This cleans up the audio device stuff */
  103.    {
  104.       for(k=3;k>(-1);k--)
  105.       {
  106.          if((sound[k])&&(sound[k]->ioa_Request.io_Device))
  107.             AbortIO((struct IORequest *)sound[k]);
  108.       }
  109.       if(sound[0]->ioa_Request.io_Device)
  110.          CloseDevice((struct IORequest *)sound[0]);
  111.       for(k=3;k>(-1);k--)
  112.       {
  113.          if(sound[k]->ioa_Request.io_Message.mn_ReplyPort)
  114.             DeletePort(sound[k]->ioa_Request.io_Message.mn_ReplyPort);
  115.       }
  116.       for(k=3;k>(-1);k--)
  117.       {
  118.          if(sound[k]) 
  119.                 FreeMem(sound[k],(long)sizeof(struct IOAudio));
  120.          if(cbuf[k])  
  121.                 FreeMem(cbuf[k],BUFSIZE);
  122.       }
  123.       sound[0]=sound[1]=sound[2]=NULL;
  124.    }
  125.  
  126. /* Write any message to out. May be error or could be samples/second */
  127. /* You'll be sorry if you try to Write(Output()) to WorkBench!  8-)  */
  128.  
  129. //   if(help) Write(Output(),string,(long)strlen(string));
  130. //   else if(strlen(string)>10L)
  131. //   {
  132. //      strcpy(title,"Sound Error: ");   strcat(title,string);
  133. //      setStatusWindo();  Delay(128L);   sound[3]=NULL;
  134. //   }
  135.  
  136. /* Clean up everything else */
  137.  
  138. //   if(StatusWindo)      CloseWindow(StatusWindo);
  139. //   if(IntuitionBase)    CloseLibrary(IntuitionBase);
  140.    if(sFile)            Close((BPTR)sFile); 
  141.    if(sbuffer)          FreeMem(sbuffer,sactual);
  142.    if(infofile)         FreeDiskObject(infofile);
  143. //   if(IconBase)         CloseLibrary(IconBase);
  144.    if(!sound[3])        snd_quit(NULL);
  145.  
  146. /* Reset everything in case we are returning (WB multiple select) */
  147.  
  148. //   StatusWindo=NULL;   // IntuitionBase=NULL;
  149.    sbuffer=NULL;   infofile=NULL; 
  150.    sactual=0L; sstart=0L; savelock=NULL; sps=0L; cycles=1L;
  151.    lock=0L; k=0; stereo=0; left=1; right=1; startvol=endvol=vol=64L;
  152. }
  153.  
  154.  
  155. void doSound(effect,loud)
  156. short loud;
  157. char *effect;
  158. {
  159.     svol = loud;
  160.     loadSound(effect);
  161.     soundSound();
  162.     snd_quit(effect);
  163. }
  164.  
  165. /*  Don't Allocate if Low Mem - by Bryce Nesbitt  */
  166. /* Aberations by RLS. 4096 should be fudge enough */
  167.  
  168. char *SafeAllocMem(size,flags)
  169. long size, flags;
  170. {
  171.    register char *p;
  172.    
  173.    if(p=(char *)AllocMem(size,flags))
  174.       if(AvailMem(MEMF_CHIP)<4096L) {FreeMem(p,size); return(NULL);}
  175.    return(p);
  176. }
  177.  
  178. /* This routine de-compresses Fibonacci Delta data, 1 byte at a time */
  179. /* x is the top nibble, y is the bottom. You get 2, 2, 2 bytes from one! */
  180.  
  181. short decomp(sbuff,i,j,zz)
  182. char *sbuff;
  183. long i,j;
  184. short zz;
  185. {
  186. short x,y;
  187.  
  188.    x=((sbuff[i])>>4)&15;          y=(sbuff[i])&15;
  189.    sbuff[j]=comptable[x]+zz;        zz=sbuff[j];
  190.    sbuff[j+1L]=comptable[y]+zz;  return(sbuff[j+1L]);
  191. }
  192.  
  193.  
  194.  
  195. /******** Load SoundFile 'sPath' & set cycles-sps-stereo *******/
  196.  
  197. void loadSound(sPa)
  198. char    *sPa;
  199. {
  200.    struct FileInfoBlock *finfo=NULL;
  201.    struct FileLock      *lock=NULL;
  202.           long          i, j;
  203.           char          string[5], sPath[80];
  204.           short         z;
  205.  
  206. /* Allocate 256 bytes as work memory */
  207.  
  208.    strcpy(sPath,sPa);
  209.    if(!(sbuffer=SafeAllocMem(256L,MEMF_CLEAR|MEMF_PUBLIC)))
  210.         snd_quit("No Work Memory!");
  211.  
  212. /* Check for and parse IFF data in first 256 bytes of file */
  213.  
  214.    if(!(sFile=(struct Filehandle *)Open(sPath,MODE_OLDFILE)))
  215.    {
  216.       sactual=256L;      snd_quit("Can't Find SoundFile!");
  217.    }
  218.    Read((BPTR)sFile,sbuffer,256L);        /* load the 1st 256 bytes */
  219.    for(sstart=0L, sps=0L, i=0L; i<252L; i+=4L)
  220.    {
  221.       strncpy(string,sbuffer+i,4);   string[4]=NULL;
  222.       if(!(strcmp(string,"VHDR")))        /* get samples per second */
  223.       {
  224.          for(j=0L;j<(long)((UBYTE)sbuffer[i+20]);j++) sps+=256L;
  225.          sps += (long)((UBYTE)sbuffer[i+21L]);
  226.          if(sbuffer[i+23L]==1) compflag=1;
  227.          if(sbuffer[i+27L]!=1)
  228.             startvol=(64L*(long)(sbuffer[i+28L]*10+sbuffer[i+29L]))/100L;
  229.       }
  230.       if(!(strcmp(string,"CHAN")))            /* Channel Assignment */
  231.       {
  232.          if((sbuffer[i+7L]==6)||(sbuffer[i+11L]==6)) stereo=1;
  233.       }
  234.       if(!(strcmp(string,"BODY")))        /* get size of sound data */
  235.       {
  236.          for(j=0L;j<4L;j++)
  237.             sactual+=((long)((UBYTE)sbuffer[i+7L-j])<<(8*j));
  238.          sstart = i+8L; i=252L;
  239.       }
  240.    }
  241.  
  242. /* if not in IFF format, get filesize from FileInfoBlock */
  243.  
  244.    if(!sactual)
  245.    {
  246.  
  247. /* Allocate a file info block, get size from it, and de-allocate */
  248.  
  249.       if((!(finfo=(struct FileInfoBlock *)
  250.          SafeAllocMem((long)sizeof(struct FileInfoBlock),MEMF_CLEAR)))
  251.        ||(!(lock=(struct FileLock *)Lock(sname,ACCESS_READ)))
  252.        ||(!(Examine((BPTR)lock,finfo))) )
  253.                     snd_quit("FileInfoBlock Problem!");
  254.       sactual = finfo->fib_Size;      if(lock) UnLock((BPTR)lock);
  255.       if(finfo) FreeMem(finfo,(long)sizeof(struct FileInfoBlock));
  256.    }
  257.  
  258. /* clean up work area */
  259.  
  260.    FreeMem(sbuffer,256L); sbuffer=NULL;
  261.    if(compflag) sactual=sactual*2L;
  262.  
  263. /* Allocate memory for SOUND data. */
  264. /* Later we'll transfer in BUFSIZE chunks to contiguous CHIP memory. */
  265.  
  266.    if(AvailMem(MEMF_LARGEST)<(sactual+16384L)) direct=1;
  267.    if(direct) return;
  268.    if(!(sbuffer=SafeAllocMem(sactual,MEMF_CLEAR|MEMF_PUBLIC)))
  269.               snd_quit("Memory Allocation Failed!");
  270.  
  271. /* Load the data into sbuffer */
  272.  
  273.    Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
  274.    if((Read((BPTR)sFile,sbuffer,sactual)) == -1L) snd_quit("Read Error!");
  275.    Close((BPTR)sFile);  sFile=NULL;
  276.  
  277. /* decompression */
  278.  
  279.    if(compflag)
  280.    {
  281. //      if(statusline) 
  282. //      {
  283. //         strcpy(title,"Processing Fibonacci Delta Compression");
  284. //         setStatusWindo();
  285. //      }
  286.       if(stereo)
  287.       {
  288.          memcpy(sbuffer+(3L*sactual)/4L,sbuffer+(sactual/4L),sactual/4L);
  289.          memcpy(sbuffer+(sactual/4L),sbuffer,sactual/4L);
  290.          j=1L;  sbuffer[0]=sbuffer[j];  z=sbuffer[j];
  291.          for(i=sactual/4L+2L;i<(sactual/2L);i++,j+=2L)
  292.             z=decomp(sbuffer,i,j,z);
  293.          j=sactual/2L; sbuffer[j]=sbuffer[(3L*sactual)/4L+1L];
  294.          z=sbuffer[j];  j++;
  295.          for(i=(3L*sactual)/4L+2L;i<sactual;i++,j+=2L)
  296.             z=decomp(sbuffer,i,j,z);
  297.       }
  298.       else
  299.       {
  300.          memcpy(sbuffer+(sactual/2L),sbuffer,sactual/2L);
  301.  
  302. /* 1st byte is pad, 2nd byte is 1st value. FOR EACH STEREO SIDE! */
  303.  
  304.          for(i=sactual/2L+2L,j=1L,z=sbuffer[1];i<sactual;i++,j+=2L)
  305.             z=decomp(sbuffer,i,j,z);
  306.       }
  307.    }
  308. }
  309.  
  310.  
  311. /*****************  make a noise ******************/
  312.  
  313. void soundSound()
  314. {
  315.     //ULONG   class;
  316.     LONG    i, j, dactual, dlength, remaining;
  317.     USHORT  count;
  318.     short   z;
  319.  
  320. /* Make sure we have valid values before 'sounding' */
  321.  
  322.     if(left==right) left=right=1;
  323.     if((sps<56L)||(sps>65534L)) sps=10000L;
  324.     if((startvol<1L)||(startvol>64L)) startvol=64L;
  325.     vol=svol;
  326.     //vol=startvol;
  327.     if((endvol<1L)||(endvol>64L)) endvol=64L;
  328.     if(direct)
  329.     {
  330.        BUFSIZE=AvailMem(MEMF_CHIP|MEMF_LARGEST)/6L;
  331.        if(BUFSIZE>64000L) BUFSIZE=64000L;
  332.        BUFSIZE-=(BUFSIZE%8L);
  333.     }
  334.  
  335. /* cycles<56 limit only applies to CLI */
  336.  
  337.     if((cycles<0L)||(cycles>65535L)) cycles=1L;
  338.     if(cycles>1L) fadevol=(endvol-startvol)/(cycles-1L);
  339.     else fadevol=0L;
  340.  
  341. /* Put up a 'status' window on the top line. */
  342.  
  343. //    if(statusline) {maketitle(); setStatusWindo();}
  344.  
  345. /* Allocate sound data buffers from CHIP memory. Ports and */
  346. /* Audio Request Structures do NOT require CHIP memory */
  347.  
  348.    for(k=0;k<4;k++)
  349.    {
  350.      if(!(cbuf[k]=SafeAllocMem(BUFSIZE,
  351.            MEMF_CHIP|MEMF_CLEAR|MEMF_PUBLIC))) snd_quit("No CHIP Memory!");
  352.      if(!(sound[k]=(struct IOAudio *)SafeAllocMem((long)sizeof(struct IOAudio),
  353.                      MEMF_CLEAR|MEMF_PUBLIC))) snd_quit("No IOA Memory!");
  354.      if(!(sound[k]->ioa_Request.io_Message.mn_ReplyPort =
  355.                   CreatePort(portname[k],0L))) snd_quit("No Port Memory!");
  356.    }
  357.  
  358. /* Open Audio using the first IOAudio as the 'initializer' request */
  359.  
  360.    sound[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 114;
  361.    if(!right) sound[0]->ioa_Data   = &sunitL[0];
  362.    else if(!left) sound[0]->ioa_Data   = &sunitR[0];
  363.    else sound[0]->ioa_Data   = &sunit[0];
  364.    sound[0]->ioa_Length = 4L;
  365.    if((OpenDevice(AUDIONAME,0L,(struct IORequest *)sound[0],0L))!=NULL)
  366.    {
  367.       sound[0]->ioa_Request.io_Device=NULL;  /* don't AbortIO if no open */
  368.       snd_quit("No Audio Device!");
  369.    }
  370.  
  371. /* Set all IOAudios. */
  372.  
  373.    for(k=0;k<4;k++)
  374.    {
  375.       sound[k]->ioa_Request.io_Message.mn_Node.ln_Pri = 114;
  376.       sound[k]->ioa_Request.io_Command = CMD_WRITE;
  377.       sound[k]->ioa_Request.io_Flags   = ADIOF_PERVOL;
  378.  
  379. /* Note copies of Device & AllocKey from initializer. */
  380.  
  381.       sound[k]->ioa_Request.io_Device  = sound[0]->ioa_Request.io_Device;
  382.       sound[k]->ioa_AllocKey  = sound[0]->ioa_AllocKey;
  383.  
  384. /* Each IOAudio has its own CHIP buffer, Port, and Unit (left/right) */
  385.  
  386.       sound[k]->ioa_Data   = (UBYTE *)cbuf[k];
  387.  
  388. /* 3579547 divided by 55 = 65083, nearly the maximum Period (65535)  */
  389. /* changing this 'magic' number is all we need to make it 'European' */
  390.  
  391. //      if(GfxBase->DisplayFlags&PAL) sound[k]->ioa_Period=3546895L/sps;
  392.     
  393.     sound[k]->ioa_Period=3579547L/sps;
  394.  
  395. /* allow for volume setting. gives us effect possibilities in a script */
  396.  
  397.       sound[k]->ioa_Volume = startvol;
  398.  
  399. /* One time through this BUFSIZE (or smaller) part of the whole */
  400.  
  401.       sound[k]->ioa_Cycles = 1L;
  402.    }
  403.  
  404. /* The compiler wants 'Unit' to be a structure, we just want to mask */
  405. /* into the allocated left/right channels. left=1 or 8, right=2 or 4 */
  406. /*        ...zap! You're a Unit structure! Feel any different?       */
  407.  
  408.    for(k=2;k>(-1);k-=2)
  409.    {
  410.       if(right) sound[k+1]->ioa_Request.io_Unit = (struct Unit *)
  411.                       ((ULONG)(sound[0]->ioa_Request.io_Unit)&6L);
  412.       if(left)    sound[k]->ioa_Request.io_Unit  = (struct Unit *)
  413.                       ((ULONG)(sound[0]->ioa_Request.io_Unit)&9L);
  414.    }
  415.  
  416. /* If in STEREO, split file. If in MONO, 'b' buffers use 'a' data */
  417.  
  418.    if(stereo) remaining=(sactual/2L)-(sactual&1L);
  419.    else
  420.    {
  421.       remaining=sactual;
  422.       sound[1]->ioa_Data   = (UBYTE *)cbuf[0];
  423.       sound[3]->ioa_Data   = (UBYTE *)cbuf[2];
  424.    }
  425.  
  426. /* dactual is the length of one channel's complete data */
  427.  
  428.    dactual=remaining;     k=count=0;
  429.  
  430. /* if DIRECT_FROM_DISK, start at the beginning of the sample */
  431.  
  432.    if(direct) Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
  433.  
  434. /* we be doing loops here */
  435.  
  436.    do
  437.    {
  438.  
  439. /* be CERTAIN ioa_Length is an even number & set datalength */
  440.  
  441.       if(remaining>BUFSIZE) dlength=BUFSIZE;
  442.       else {dlength=remaining; dlength-=(dlength&1L);}
  443.  
  444. /* Move the data into the proper CHIP buffer of BUFSIZE */
  445.  
  446.       if(direct)
  447.       {
  448.          if(stereo) Seek((BPTR)sFile,sstart+dactual-remaining,
  449.                              OFFSET_BEGINNING);
  450.          if(compflag)
  451.          {
  452.             Read((BPTR)sFile,cbuf[k]+dlength/2L,dlength/2L);
  453.             if(remaining==dactual)
  454.                {z=cbuf[k][1L+dlength/2L]; cbuf[k][0]=z; i=2L; j=1L;}
  455.             else {i=0L; j=0L;}
  456.             for(;i<(dlength/2L);i++,j+=2L)
  457.                z=decomp(cbuf[k],i+dlength/2L,j,z);
  458.          }
  459.          else Read((BPTR)sFile,cbuf[k],dlength);
  460.       }
  461.       else movmem(sbuffer+(dactual-remaining),cbuf[k],(int)dlength);
  462.  
  463. /* Don't load or use the right CHIP buffers if MONO. Saves time. */
  464.  
  465.       if(stereo)
  466.       {
  467.          if(direct)
  468.          {
  469.             if(compflag)
  470.             {
  471.                Seek((BPTR)sFile,sstart+dactual+dactual/2L-remaining,
  472.                       OFFSET_BEGINNING);
  473.                Read((BPTR)sFile,cbuf[k+1]+dlength/2L,dlength/2L);
  474.                if(remaining==dactual)
  475.                   {z=cbuf[k+1][1L+dlength/2L]; cbuf[k+1][0]=z; i=2L; j=1L;}
  476.                else {i=0L; j=0L;}
  477.                for(;i<(dlength/2L);i++,j+=2L)
  478.                   z=decomp(cbuf[k+1],i+dlength/2L,j,z);
  479.             }
  480.             else
  481.             {
  482.                Seek((BPTR)sFile,sstart+sactual-remaining,OFFSET_BEGINNING);
  483.                Read((BPTR)sFile,cbuf[k+1],dlength);
  484.             }
  485.          }
  486.          else movmem(sbuffer+(sactual-remaining),cbuf[k+1],(int)dlength);
  487.       }
  488.  
  489. /* Data has been moved, so adjust 'remaining' */
  490.  
  491.       remaining-=dlength;
  492.  
  493. /* Left and Right Lengths are the same, no matter what! */
  494.  
  495.       sound[k]->ioa_Length = sound[k+1]->ioa_Length = dlength;
  496.  
  497. /* Start one set of Left/Right Channels. */
  498.  
  499.       if(left)  BeginIO((struct IORequest *)sound[k]);
  500.       if(right) BeginIO((struct IORequest *)sound[k+1]);
  501.  
  502. /* If no QUIET flag, Check Intuition for the ABORT message */
  503.  
  504. //      if(statusline)
  505. //      {
  506. //      while(message=(struct IntuiMessage *)GetMsg(StatusWindo->UserPort))
  507. //         {
  508. //            class = message->Class;  code = message->Code;
  509.  
  510. /* Hi Intuition! Thanks for the message, Have a nice day! */
  511.  
  512. //            ReplyMsg((struct Message *)message);
  513.  
  514. /* <CTRL> 'c' abort.  1,2,3, easy as a,b,c, baby you and me! */
  515.  
  516. //            if((class==VANILLAKEY)&&(code==3)) snd_quit("");
  517. //         }
  518. //      }
  519.       if(fade!=0L)
  520.          {vol=(64L*remaining)/dactual;  if(fade>0L) vol=64L-vol;}
  521.  
  522. /* Is this the last time AND the last cycle? If yes & no, reset. */
  523.  
  524.       if(remaining<2L)
  525.       {
  526.          cycles--;
  527.          if(cycles!=0L)
  528.          {
  529.             if(direct) Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
  530.             remaining=dactual; dlength=BUFSIZE;
  531.             if(fadevol!=0L)
  532.             {
  533.                vol=vol+fadevol;
  534. //               if(statusline) {maketitle(); setStatusWindo();}
  535.             }
  536.          }
  537.       }
  538.       if(vol>64L) vol=64L;  if(vol<1L) vol=1L;
  539.       for(i=0L;(i<4L)&&(vol>=0L);i++) sound[i]->ioa_Volume = vol;
  540.  
  541. /* Is this the last time, or what? */
  542.  
  543.       if(remaining<2L)
  544.          WaitIO((struct IORequest *)sound[k+right]); /* wait for LAST request */
  545.       else
  546.       {
  547.          if(k) k=0; else k=2;    /* switch buffers & wait for PREVIOUS */
  548.          if(count++) WaitIO((struct IORequest *)sound[k+right]);
  549.       }
  550.  
  551. /* Keep going until we run out of data */
  552.  
  553.    } while(remaining>1L);                   /* End of Loop */
  554. }
  555.  
  556.  
  557. /********** long int to char string (up to 10 digits) ***********/
  558.  
  559. char *ltoa(num)
  560.           long  num;
  561. {
  562.    static char ostring[11]="";
  563.           short  next = 10,  shift = 0;
  564.    
  565.    if (!num) ostring[next--] = '0';
  566.    while ((num+9L)/10)
  567.       { ostring[next--] = num % 10L + '0';   num /= 10L; }
  568.    next+=1;
  569.    while(next<11)       ostring[shift++] = ostring[next++];
  570.    while(shift<11)      ostring[shift++] = '\0';
  571.    return(ostring);
  572. }
  573.  
  574.  
  575. /************************** end of Sound.c ******************************/
  576.